const categoryNames = [
  'Art and design',
  'Living and dying',
  'Power and identity',
  'Religion and belief',
  'Trade and conflict'
];

const scrollHelp = false;
const hoverInfoObject = null;
const yearIntervals = [
  {start: 2100, end: -100, yearLength: 0.3},
  {start: -100, end: -500, yearLength: 0.2},
  {start: -500, end: -1000, yearLength: 0.1},
  {start: -1000, end: -5000, yearLength: 0.025},
  {start: -5000, end: -5e6, yearLength: 0.0002}
];
const introLength = 14000;


function InitWebGl () {
  var xorgen = new xor4096('heabllo.');
  var loaderXorgen = new xor4096('alflog.');
  var objectXorgen = new xor4096('hello.');
  var self = this;

  this.yearIntervals = yearIntervals
  this.introTime = 0;
  this.cameraY = 0;
  this.cameraZMotion = 0;
  this.cameraZTarget = null;
  this.cameraXOffset = 0;
  this.cameraYOffset = 0.5;

  this.loadingPercentageMax = 0;


  window.onresize = function() {

    self.halfX = window.innerWidth / 2;
    self.halfY = window.innerHeight / 2;

    self.width = window.innerWidth;
    self.height = window.innerHeight;

    self.camera.aspect = self.width / self.height;
    self.camera.updateProjectionMatrix();

    self.renderer.setSize( self.width, self.height );

    self.landscapeShaderMaterial.uniforms.scale.value = self.renderer.domElement.width / 1000;
  };
  this.yearZeroOffsets = [
    0, -50, -40, -30, -20, -10, 0, 10, 20, 30, 40, 50
  ];
  this.yearZeroOffsetIndex = 0;

  this.mapYearToLandscapeZ = function(year, offset) {
    year = year || 0;
    if (year === 0 && offset) {
      year += this.yearZeroOffsets[this.yearZeroOffsetIndex];
      this.yearZeroOffsetIndex = (this.yearZeroOffsetIndex + 1) % this.yearZeroOffsets.length;
    }
    var z = 0;
    for (var i=0; i<this.yearIntervals.length; i++) {
      var iv = this.yearIntervals[i];
      if (year > iv.start) {
        break;
      }
      var d = Math.min(iv.start - iv.end, iv.start - year);
      z += d * iv.yearLength;
    }
    return 1900*0.2 + 100*0.3 + 50*0.4 + 50*0.8 - z;
  };

  this.tick = this.tick.bind(this);

  this.init(true);
}

InitWebGl.prototype.init = function(skipChecks) {

  this.now = (
    (window.performance && window.performance.now && window.performance.now.bind(window.performance)) ||
    Date.now.bind(Date)
  );

  this.lastFrameTime = this.now();

  // $scope.screenSizeWarning = false;

  if (!skipChecks && (window.innerWidth < 770 || /mobile|iPad|iPhone|Android/i.test(navigator.userAgent))) {
    // $scope.screenSizeWarning = true;
    return;
  }

  // $scope.webgl = Detector.webgl;
  if (!Detector.webgl){
    return;
  }

  if (!this.initDone) {
    var self = this;

    this.geographies = ['Africa', 'Americas', 'Asia', 'Europe', 'Oceania'];
    this.geoLane = {};
    this.geographies.forEach(function(e,i) { self.geoLane[e] = i; });
    this.colors = [
      0xFFBA0A, 0xF14F11, 0x8DC73C, 0x0071BC, 0x9E005D
    ];

    var blobTextures = [];
    for (var i=0; i<16; i++) {
      var tex = new THREE.ImageUtils.loadTexture('http://localhost:5000/img/blob_'+ i +'.png', undefined, function() {
        self.loadingPercentageMax += 2;
      }, function() {
        self.loadingPercentageMax += 2;
      });
      tex.premultiplyAlpha = true;
      blobTextures.push(tex);
    }
    this.blobTextures = blobTextures;
    /**
     * 环境着色器
     * @type {THREE.ShaderMaterial}
     */
    this.landscapeShaderMaterial = landscapeShaderMaterial

    /**
     * 素材着色器
     * @type {THREE.ShaderMaterial}
     */
    this.canvasShaderMaterial = canvasShaderMaterial

    /**
     * 线条着色器
     * @type {THREE.ShaderMaterial}
     */
    this.lineShaderMaterial = lineShaderMaterial
  }

  // $scope.cameraMotionType = 'onlyTerrain';
  // $scope.cameraMotionType = 'resizing2DToolBar';
  // $scope.cameraMotionType = 'fixed2DToolBar';
  // $scope.cameraMotionType = '3DToolBar';

  // $scope.hoverInfoX = 0;
  // $scope.hoverInfoY = 0;

  // $scope.loadingPercentage = 0;

  if (!this.initDone) {
    this.initDone = true;

    this.initWebGL();
    window.onresize();

    fetch('http://localhost:5000/js/landscapeCoords.json').then(res => res.json()).then(function(object) {
      console.log('js/landscapeCoords.json', object)
      initTerrain.call(self, object);
      self.loadingPercentageMax += 50;
    }, function(err) {
      console.log("Failed to load terrain geometry.")
    });

    this.tick();
  }
};

InitWebGl.prototype.initWebGL = function() {
  var renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setPixelRatio(window.devicePixelRatio || 1);

  this.lastFrameTime = this.now();
  this.frameElapsed = 0;

  var width = window.innerWidth;
  var height = window.innerHeight;

  renderer.setSize(width, height);

  renderer.setClearColor(0x66685D, 1.0);

  this.renderer = renderer;

  this.halfX = width / 2;
  this.halfY = height / 2;

  this.width = width;
  this.height = height;

  if (this.width > this.height) {
    this.cameraYOffset = 1;
  }

  renderer.domElement.id = 'main-canvas';
  document.body.appendChild(renderer.domElement);

  this.itemGeometry = new THREE.PlaneBufferGeometry(1, 1);
  this.initScene();

  return true;
};

InitWebGl.prototype.initScene = function() {
  var scene = new THREE.Scene();
  scene.frustumCulled = false;
  var camera = new THREE.PerspectiveCamera(50, this.width/this.height, 1, 3000);
  camera.position.z = 100;
  camera.position.y = 2;

  camera.target = new THREE.Vector3();
  camera.target.copy(camera.position);

  scene.fog = new THREE.Fog(0x66685D, 100, 400);

  window.camera = camera;
  scene.add(camera);

  this.labelScene = new THREE.Scene();
  this.labelScene.fog = scene.fog;

  this.scene = scene;
  this.camera = camera;
  this.cameraVelocity = new THREE.Vector3();

  /*this.scene.tick = function() {
    for (var i=0; i<this.children.length; i++) {
      if (this.children[i].tick) {
        this.children[i].tick();
      }
    }
  };*/
};

InitWebGl.prototype.render = function() {
  this.renderer.autoClear = false;
  this.renderer.clear();
  this.renderer.render(this.scene, this.camera);
  this.renderer.render(this.labelScene, this.camera);
};

InitWebGl.prototype.tick = function(t, el, secondTick) {

  var cameraMinZ = this.mapYearToLandscapeZ(-2e6) + 40;
  var cameraMaxZ = this.mapYearToLandscapeZ(2015) + 40;

  /*this.active = ($location.path().replace("/","") === '');
  if (!this.objects || !this.active) {
    this.renderer.clear();
    window.requestAnimationFrame(this.tick);
    return;
  }*/
  var scene = this.scene;
  var camera = this.camera;
  var introState = 3 // $scope.introState;
  var introTime = this.introTime;
  var cameraY = this.cameraY;
  var cameraZMotion = this.cameraZMotion;
  var cameraZTarget = this.cameraZTarget;

  if (this.introTime > 3000 && this.audioManager) {
    this.audioManager.start();
  }

  if (this.introTime < this.introLength + 16) {
    introTime = Math.max(0, this.introTime - (this.introLength - 3000));


    camera.position.y = Math.max(cameraY, cameraY + 40 * Math.pow(Math.max(0, 1-introTime/3000), 3.0));
    camera.position.z = (this.mapYearToLandscapeZ(2015)
      + 28
      + -800 * Math.max(0, 1-Math.pow(introTime/3000, 2))
    );

    camera.target.x = 0;
    camera.target.y = camera.position.y + 40 * (1-introTime/3000) - 10;
    camera.target.z = camera.position.z - 50;

    this.lines.position.z = this.camera.position.z;

    camera.lookAt(camera.target);

    if (introState >= 2) {
      this.introTime += 16;
    }

    if (this.introBlobs) {
      this.introBlobs.position.copy(camera.target);
      this.introBlobs.lookAt(camera.position);
    }
  }

  camera.position.z += cameraZMotion * 0.1;
  if (cameraZMotion > 0 && cameraZMotion < 20) {
    cameraZMotion += 0.25;
  } else if (cameraZMotion < 0 && cameraZMotion > -20) {
    cameraZMotion -= 0.25;
  }
  if (cameraZMotion === 0) {
    if (cameraZTarget && Math.abs(cameraZTarget-camera.position.z) < 0.001) {
      cameraZTarget = null;
    }
    if (cameraZTarget !== null) {
      camera.position.z += (cameraZTarget - camera.position.z) * 0.05;
    }
  }
  this.cameraZMotion = cameraZMotion;
  this.cameraZTarget = cameraZTarget;

  if (this.introTime >= this.introLength + 16) {
    this.linesPlane.visible = false;

    camera.position.z += this.cameraVelocity.z;

    if (Math.abs(this.cameraVelocity.z) < 1) {
      this.cameraVelocity.z *= 0.9;
    } else {
      this.cameraVelocity.z *= 0.95;
    }

    if (Math.abs(this.cameraVelocity.z) < 0.01) {
      this.cameraVelocity.z = 0;
    }

    this.cameraXOffset += this.cameraVelocity.x;
    if (this.cameraXOffset > 1) this.cameraXOffset = 1;
    if (this.cameraXOffset < -1) this.cameraXOffset = -1;
    this.cameraVelocity.x *= 0.9;

    camera.position.x += (this.cameraXOffset * 10 - camera.position.x) * 0.05;
    camera.position.y += (cameraY + 8 + this.cameraYOffset * 3 - camera.position.y) * 0.05;

    camera.target.x += (Math.sin(this.cameraXOffset * 0.5) * 30 - camera.target.x) * 0.1;
    camera.target.y += (cameraY + 8 - 20 + this.cameraYOffset * 5 - camera.target.y) * 0.1;
    camera.target.z = camera.position.z - Math.cos(this.cameraXOffset * 0.5) * 50;

    camera.lookAt(camera.target);

    camera.updateProjectionMatrix();
    camera.updateMatrix();

    this.labels.visible = true;
    this.toolBar3D.visible = true;
    this.labels.position.z = camera.position.z - 25;
    this.toolBar3D.position.z = camera.position.z - 25;

    this.lines.position.z = this.toolBar3D.position.z;

    if (camera.position.z > cameraMaxZ) {
      camera.position.z += (cameraMaxZ - camera.position.z) * 0.1;
    } else if (camera.position.z < cameraMinZ) {
      camera.position.z += (cameraMinZ - camera.position.z) * 0.1;
    }

    if (this.cameraZTarget > cameraMaxZ) {
      this.cameraZTarget += (cameraMaxZ - this.cameraZTarget) * 0.1;
    } else if (this.cameraZTarget < cameraMinZ) {
      this.cameraZTarget += (cameraMinZ - this.cameraZTarget) * 0.1;
    }

    /*if ($scope.hoverInfoObject) {
      var hoverInfoEl = document.getElementById('object-hover-info');
      scene.updateMatrixWorld();
      this.linesPlane.updateMatrixWorld();
      $scope.hoverInfoObject.hoverConnectionTarget.updateMatrixWorld();
      this.moveToScreenCoords( $scope.hoverInfoObject.hoverConnectionTarget, camera, hoverInfoEl.getBoundingClientRect() );
    }*/
  }

  this.landscapeShaderMaterial.uniforms.time.value += 0.016;

  // scene.tick();

  if (this.frameElapsed > 25 && (!secondTick || secondTick < 4)) {
    this.frameElapsed -= 25;
    this.tick(time, undefined, (secondTick || 0) + 1);
  } else {
    var time = this.now();
    this.frameElapsed = time - this.lastFrameTime;
    this.lastFrameTime = time;
    this.render();

    /*if ( this.findToolbarUnderEvent(this.mouseCurrent) || this.findObjectUnderEvent(this.mouseCurrent) ) {
      this.overlaysEl.style.cursor = 'pointer';
    } else {
      this.overlaysEl.style.cursor = 'default';
    }*/

    window.requestAnimationFrame(this.tick);
  }
};

var terrain = new InitWebGl();

terrain.render();
